package com.example.camera2sample

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.SurfaceTexture
import android.hardware.camera2.*
import android.os.Handler
import android.os.HandlerThread
import android.text.TextUtils
import android.util.Log
import android.util.Size
import android.view.Surface
import androidx.annotation.AnyThread
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import java.util.*
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit

class Camera2Helper(context: Context) : ICamera {

    // 获取 CameraManager 实例
    private val cameraManager: CameraManager by lazy { context.getSystemService(CameraManager::class.java) }

    companion object {
        private const val TAG = "Camera2Helper"

        private const val preViewH = 1920
        private const val previewW = 1080
    }

    private var frontCamera = false

    private var frontCameraId: String? = null
    private var backCameraId: String? = null
    private var frontCameraCharacteristics: CameraCharacteristics? = null
    private var backCameraCharacteristics: CameraCharacteristics? = null

    private var cameraDevice: CameraDevice? = null
    private var optimalSize: Size? = null
    private var mCaptureSession: CameraCaptureSession? = null

    private var cameraHandler: Handler? = null
    private var cameraThread: HandlerThread? = null
    private var mCameraOpenCloseLock: Semaphore = Semaphore(1)

    /**
     * 相机输出的画面载体
     */
    var mSurfaceTexture: SurfaceTexture? = null
    private var mSurface: Surface? = null

    /**
     * 获取摄像头ID
     */
    private fun initCameraId() {
        if (TextUtils.isEmpty(frontCameraId).not() && TextUtils.isEmpty(backCameraId).not()) {
            return
        }
        val cameraIdList = cameraManager.cameraIdList
        cameraIdList.forEach { cameraId ->
            val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId)
            if (cameraCharacteristics.isHardwareLevelSupported(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)) {
                if (cameraCharacteristics[CameraCharacteristics.LENS_FACING] == CameraCharacteristics.LENS_FACING_FRONT) {
                    frontCameraId = cameraId
                    frontCameraCharacteristics = cameraCharacteristics
                    Log.d(TAG, "initCameraId: frontCameraId = $frontCameraId")
                } else if (cameraCharacteristics[CameraCharacteristics.LENS_FACING] == CameraCharacteristics.LENS_FACING_BACK) {
                    backCameraId = cameraId
                    backCameraCharacteristics = cameraCharacteristics
                    Log.d(TAG, "initCameraId: backCameraId = $backCameraId")
                }
            }
        }
    }

    @SuppressLint("MissingPermission")
    override fun openCamera(width: Int, height: Int) {
        initCameraId()
        // 优先选择后置摄像头，其次才是前置摄像头。
        val cameraId = if (frontCamera) backCameraId else frontCameraId
        if (cameraId != null) {
            val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId)
            // 获取可预览的分辨率
            optimalSize = getPreviewSize(cameraCharacteristics)
            printCameraId(cameraCharacteristics)
            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                throw RuntimeException("Time out waiting to lock camera opening.")
            }
            cameraManager.openCamera(cameraId, CameraStateCallback(), cameraHandler)
        } else {
            throw RuntimeException("Camera id must not be null.")
        }
    }


    override fun onResume() {
        startBackgroundThread()
    }

    override fun onPause() {
        stopBackgroundThread()
        closeCamera()
    }

    override fun onRelease() {

    }

    override fun changeCamera() {
        closeCamera()
        frontCamera = !frontCamera
        openCamera(preViewH, previewW)
    }

    override fun setSurfaceTexture(surfaceTexture: SurfaceTexture) {
        this.mSurfaceTexture = surfaceTexture
    }

    private fun startBackgroundThread() {
        cameraThread = HandlerThread(TAG)
        cameraThread!!.start()
        cameraHandler = Handler(cameraThread!!.looper)
    }

    private fun stopBackgroundThread() {
        cameraThread?.quitSafely()
        try {
            cameraThread?.join()
            cameraThread = null
            cameraHandler = null
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
    }

    private fun getPreviewSize(cameraCharacteristics: CameraCharacteristics): Size? {
        val optimalSize = getOptimalSize(cameraCharacteristics, SurfaceTexture::class.java, previewW, preViewH)
        Log.e(TAG, "getPreviewSize: ${optimalSize.toString()}")
        return optimalSize
    }

    @WorkerThread
    private fun getOptimalSize(cameraCharacteristics: CameraCharacteristics, clazz: Class<*>,
                               maxWidth: Int, maxHeight: Int): Size? {
        val streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
        val supportedSizes = streamConfigurationMap?.getOutputSizes(clazz)
        return getOptimalSize(supportedSizes, maxWidth, maxHeight)
    }


    @AnyThread
    private fun getOptimalSize(supportedSizes: Array<Size>?, maxWidth: Int, maxHeight: Int): Size? {
        Log.e(TAG, "getOptimalSize: ${Arrays.toString(supportedSizes)}")
        val aspectRatio = maxWidth.toFloat() / maxHeight
        if (supportedSizes != null) {
            for (size in supportedSizes) {
                if (size.height.toFloat() / size.width == aspectRatio && size.width <= maxHeight && size.height <= maxWidth) {
                    return size
                }
            }
        }
        return null
    }

    /**
     * 打印摄像头ID
     */
    private fun printCameraId(cameraCharacteristics: CameraCharacteristics) {
        val lensFacing = cameraCharacteristics[CameraCharacteristics.LENS_FACING]
        when (lensFacing) {
            CameraCharacteristics.LENS_FACING_FRONT -> {
                Log.e(TAG, "openCamera: 前置摄像头")
            }
            CameraCharacteristics.LENS_FACING_BACK -> {
                Log.e(TAG, "openCamera: 后置摄像头")
            }
            CameraCharacteristics.LENS_FACING_EXTERNAL -> {
                Log.e(TAG, "openCamera: 外部摄像头")
            }
        }
    }

    private fun closeCamera() {
        try {
            mCameraOpenCloseLock.acquire()
            if (null != mCaptureSession) {
                mCaptureSession?.close()
                mCaptureSession = null
            }
            if (null != cameraDevice) {
                cameraDevice?.close()
                cameraDevice = null
            }
//            if (null != mImageReader) {
//                mImageReader.close()
//                mImageReader = null
//            }
        } catch (e: InterruptedException) {
            throw java.lang.RuntimeException("Interrupted while trying to lock camera closing.", e)
        } finally {
            mCameraOpenCloseLock.release()
        }
    }


    private inner class CameraStateCallback : CameraDevice.StateCallback() {
        @MainThread
        override fun onOpened(camera: CameraDevice) {
            // This method is called when the camera is opened.  We start camera preview here.
            mCameraOpenCloseLock.release()
            cameraDevice = camera
            //创建摄像头的预览会话
            createCaptureSession()
            Log.e(TAG, "onOpened: 相机开启成功")
        }

        @MainThread
        override fun onClosed(camera: CameraDevice) {
            Log.e(TAG, "onClosed: 相机关闭成功")
        }

        @MainThread
        override fun onDisconnected(camera: CameraDevice) {
            mCameraOpenCloseLock.release()
            cameraDevice!!.close()
            cameraDevice = null
            Log.e(TAG, "onDisconnected: ")
        }

        @MainThread
        override fun onError(camera: CameraDevice, error: Int) {
            mCameraOpenCloseLock.release()
            cameraDevice!!.close()
            cameraDevice = null
            Log.e(TAG, "onError: ")
        }
    }


    private fun createCaptureSession() {
        val views = mutableListOf<Surface?>()
        mSurfaceTexture?.setDefaultBufferSize(optimalSize?.width ?: previewW, optimalSize?.height
            ?: preViewH)
        mSurface = Surface(mSurfaceTexture)
        views.add(mSurface)
        cameraDevice?.createCaptureSession(views, sessionStateCallback, null)
    }


    /**
     * 创建摄像头的预览会话监听
     * Creates a new [CameraCaptureSession] for camera preview.
     */
    private val sessionStateCallback: CameraCaptureSession.StateCallback = object : CameraCaptureSession.StateCallback() {
        override fun onConfigured(session: CameraCaptureSession) {
            mCaptureSession = session
            try {
                val builder: CaptureRequest.Builder? = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
                builder?.addTarget(mSurface!!)
                val captureRequest: CaptureRequest? = builder?.build()
                if (captureRequest != null) {
                    //不断发送请求
                    session.setRepeatingRequest(captureRequest, null, null)
                }
            } catch (e: CameraAccessException) {
            }
        }

        override fun onConfigureFailed(session: CameraCaptureSession) {
        }
    }

}